package com.hyjiacan.h2c.commands

import com.hyjiacan.h2c.Cmd
import com.hyjiacan.h2c.H2
import java.io.File
import java.nio.charset.Charset
import java.sql.Date
import java.sql.Time
import java.sql.Timestamp
import java.time.format.DateTimeFormatter

class CommandExportTable : ICommand {
    override val name: String
        get() = "export"
    override val description: String
        get() = "导出指定的表到文件中。例: export table_name /path/to/file.sql"

    override fun test(string: String): Boolean {
        return string.startsWith(name)
    }

    override fun run(string: String, db: H2): Boolean {
        val temp = string.substring(name.length).trim().split(' ', limit = 2)
        if (temp.size != 2) {
            Cmd.pl("命令无效，例")
            Cmd.pl("export table_name /path/to/file.sql")
            return true
        }

        val table = temp[0]
        val filename = temp[1]

        val file = File(filename)
        val dir = file.parentFile
        if (!dir.exists()) {
            Cmd.pl("创建目录 ${dir.absolutePath}")
            dir.mkdirs()
        }
        if (file.exists()) {
            Cmd.p("文件已经存在，是否覆盖？([Y]es, No)>")
            val input = readln().trim().lowercase()
            if (input != "" && input != "y" && input != "yes") {
                return true
            }
        }

        writeData(table, db, file)

        return true
    }

    private fun writeData(table: String, db: H2, file: File) {
        Cmd.pl("正在导出表数据 $table 到文件 ${file.absolutePath} ...")
        Cmd.pl("正在查询数据 ...")

        val sql = "select * from $table"
        val result = db.execute(sql)

        Cmd.pl("共 ${result.rowsAffected} 条数据")

        val columns = result.columns!!.joinToString("`, `")

        val header = """
            -- ----------------------------------------------
            -- Exported by h2c
            -- Table: $table
            -- Count: ${result.rowsAffected}
            -- ----------------------------------------------
        """.trimIndent()

        val tpl = "INSERT INTO $table(`$columns`) VALUES(%s);\n"

        file.writer(Charsets.UTF_8).use { writer ->
            writer.write(header)
            writer.write("\n")

            result.data!!.forEach { row ->
                val values = row.map { cell ->
                    if (cell == null) {
                        return@map "NULL"
                    }
                    if (cell is Int || cell is Float || cell is Short || cell is Byte) {
                        return@map "$cell"
                    }
                    if (cell is Boolean) {
                        val v = if (cell) "true" else "false"
                        return@map "'$v'"
                    }
                    if (cell is ByteArray) {
                        val v = cell.toString(Charsets.UTF_8)
                        return@map "'$v'"
                    }
                    if (cell is Date) {
                        val v = cell.toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                        return@map "'$v'"
                    }
                    if (cell is Time) {
                        val v = cell.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"))
                        return@map "'$v'"
                    }
                    if (cell is Timestamp) {
                        val v = cell.toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
                        return@map "'$v'"
                    }
                    return@map "'$cell'"
                }

                writer.write(String.format(tpl, values.joinToString(", ")))
            }
        }
        Cmd.pl("导出完成，文件 ${file.absolutePath}")
    }
}